Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better diagnostics #2562

Merged
merged 45 commits into from
Feb 10, 2021
Merged

Better diagnostics #2562

merged 45 commits into from
Feb 10, 2021

Conversation

nlohmann
Copy link
Owner

@nlohmann nlohmann commented Jan 1, 2021

This PR improves the diagnostic information provided by the library in case of exceptions. The idea (originally described in #1508 (comment) and #932 (comment)) is that every JSON value in an array or object contains a pointer to the enclosing container. From this parent relation, we can generate a JSON Pointer to the current value that allows to identify the erroneous value. As we need to store one additional pointer per JSON value, the diagnostic mode is guarded by a preprocessor macro JSON_DIAGNOSTICS that needs to be defined in order to enable the better diagnostics.

This PR is work in progress. There are a lot of open tasks, including

  • set the parent pointer in all situations
  • find a way to deal with iterators
  • add diagnostics to exceptions
  • add tests
  • add CMake option

Any help, input, review, or discussion is greatly appreciated!

Closes #1508. Closes #932. Closes #2552.

@coveralls
Copy link

coveralls commented Jan 1, 2021

Coverage Status

Coverage remained the same at 100.0% when pulling 56a6dec on diagnostics into e754ef7 on develop.

test/src/unit-json_patch.cpp Outdated Show resolved Hide resolved
include/nlohmann/json.hpp Outdated Show resolved Hide resolved
include/nlohmann/json.hpp Outdated Show resolved Hide resolved
include/nlohmann/json.hpp Outdated Show resolved Hide resolved
@nlohmann
Copy link
Owner Author

nlohmann commented Jan 7, 2021

Thanks @gregmarr for the comments! I will look at them in detail later this week.

include/nlohmann/json.hpp Outdated Show resolved Hide resolved
include/nlohmann/json.hpp Outdated Show resolved Hide resolved
include/nlohmann/json.hpp Outdated Show resolved Hide resolved
include/nlohmann/json.hpp Outdated Show resolved Hide resolved
@karzhenkov
Copy link
Contributor

There is a missed point. The following assigment will be lost after the object is moved to the container:

(*element.m_value.array)[1].m_parent = this;

@nlohmann
Copy link
Owner Author

nlohmann commented Jan 8, 2021

There is a missed point. The following assigment will be lost after the object is moved to the container:

(*element.m_value.array)[1].m_parent = this;

Unfortunately, I cannot create an example where the parent is lost.

Would you propose setting the parent after calling emplace?

@karzhenkov
Copy link
Contributor

karzhenkov commented Jan 8, 2021

I think it can be done something like this: karzhenkov/json@22bd1e1

include/nlohmann/json.hpp Outdated Show resolved Hide resolved
@nlohmann nlohmann marked this pull request as ready for review January 23, 2021 09:05
@nlohmann
Copy link
Owner Author

@gregmarr @karzhenkov I think this branch is ready now. Any further comment or observation?

doc/examples/diagnostics_extended.link Show resolved Hide resolved
include/nlohmann/detail/diagnostics_t.hpp Outdated Show resolved Hide resolved
include/nlohmann/detail/diagnostics_t.hpp Outdated Show resolved Hide resolved
@karzhenkov
Copy link
Contributor

Here are also some proposals to undo unnecessary changes and make the code a bit more concise: karzhenkov#1

@nlohmann
Copy link
Owner Author

nlohmann commented Jan 25, 2021

Here are also some proposals to undo unnecessary changes and make the code a bit more concise: karzhenkov#1

I took over some of your ideas: 74cc0ab. What do you think?

@karzhenkov
Copy link
Contributor

karzhenkov commented Jan 26, 2021

It would also be nice to get rid of the empty json objects that are created in many places just to indicate "no diagnostics". This can be achieved with an overload of exception::diagnostics taking std::nullptr_t and with some defaults (BasicJsonType = std::nullptr_t; context = nullptr) here:

template<typename BasicJsonType>
static parse_error create(int id_, const position_t& pos, const std::string& what_arg, const BasicJsonType& context)

Other similar function templates need the same defaults.

As a possible point of additional extension, we can also consider other types of context that may be appropriate if no relevant json object is available.

Copy link
Contributor

@gregmarr gregmarr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ugh, started a review yesterday and forgot to submit it.

include/nlohmann/detail/exceptions.hpp Outdated Show resolved Hide resolved
include/nlohmann/detail/exceptions.hpp Outdated Show resolved Hide resolved
include/nlohmann/detail/exceptions.hpp Outdated Show resolved Hide resolved
@@ -137,7 +137,7 @@ class binary_reader
if (JSON_HEDLEY_UNLIKELY(current != std::char_traits<char_type>::eof()))
{
return sax->parse_error(chars_read, get_token_string(),
parse_error::create(110, chars_read, exception_message(format, "expected end of input; last byte: 0x" + get_token_string(), "value")));
parse_error::create(110, chars_read, exception_message(format, "expected end of input; last byte: 0x" + get_token_string(), "value"), BasicJsonType()));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this just be {} instead of BasicJsonType()? (Not sure now what works in C++11 and what requires later versions.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm assuming that you want to be explicit about not providing a json object here and so don't want a default parameter value.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried earlier to work with a default value, but I got an error that the type could not be derived. I'll give it another check later.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, it's a templated parameter, yeah that makes it harder to have a default.

@gregmarr
Copy link
Contributor

gregmarr commented Feb 9, 2021

LGTM

@nlohmann nlohmann merged commit 176d8e2 into develop Feb 10, 2021
@nlohmann nlohmann deleted the diagnostics branch February 10, 2021 06:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants